home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / More Source / C⁄C++ / Xconq 7.0d37 / source / mac / maclist.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-13  |  21.8 KB  |  857 lines  |  [TEXT/KAHL]

  1. /* Unit lists for the Mac interface to Xconq.
  2.    Copyright (C) 1992, 1993, 1994 Stanley T. Shebs.
  3.  
  4. Xconq is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.  See the file COPYING.  */
  8.  
  9. #include "conq.h"
  10. #include "macconq.h"
  11.  
  12. /* (should be adjusted for expected range of values) */
  13.  
  14. int curactcolw = 10;
  15. int imagecolw = 20;
  16. int namecolw = 100;
  17. int typecolw = 70;
  18. int sidecolw = 70;
  19. int hpcolw = 40;
  20. int acpcolw = 60;
  21. int poscolw = 60;
  22. int supcolw = 40;
  23. int notecolw = 50;
  24.  
  25. /* Sum of non-scrolling field widths. */
  26.  
  27. int fixedfieldwidth;
  28.  
  29. /* Sum of all field widths. */
  30.  
  31. int maxlistwidth;
  32.  
  33. /* The height of the headings lines at the top of the window. */
  34.  
  35. int listtoph = 20;
  36.  
  37. int listtopbaseline = 13;
  38.  
  39. /* The possible heights of each individual list entry. */
  40.  
  41. int smallentryspacing = 18;
  42. int largeentryspacing = 34;
  43.  
  44. int listnum = 1;
  45.  
  46. int lastlisth = -1, lastlistv = -1;
  47.  
  48. /* Create a new list of units. */
  49.  
  50. void
  51. create_list()
  52. {
  53.     int i;
  54.     List *list = (List *) xmalloc(sizeof(List));
  55.     Rect hscrollrect, vscrollrect;
  56.  
  57.     maxlistwidth = 0;
  58.     maxlistwidth += curactcolw;
  59.     maxlistwidth += imagecolw;
  60.     maxlistwidth += namecolw;
  61.     fixedfieldwidth = maxlistwidth;
  62.     maxlistwidth += typecolw;
  63.     maxlistwidth += sidecolw;
  64.     maxlistwidth += hpcolw;
  65.     maxlistwidth += acpcolw;
  66.     maxlistwidth += poscolw;
  67.     maxlistwidth += nummtypes * supcolw;
  68.     maxlistwidth += notecolw;
  69.  
  70.     DGprintf("Creating a list\n");
  71.     list->sides == -1L;  /* lists every side and indeps too */
  72.     for (i = 0; i < MAXSORTKEYS; ++i) {
  73.         list->sortkeys[i] = bynothing;
  74.     }
  75.     list->sortkeys[0] = byside;
  76.     list->mainsortmi = miViewBySide;
  77.     list->listglimpsed = FALSE;
  78.     list->largeicons = FALSE; /* (should be a preference) */
  79.     list->entryspacing = (list->largeicons ? largeentryspacing : smallentryspacing);
  80.     list->firstvisible = 0;
  81.     init_list_contents(list);
  82.     organize_list_contents(list);
  83.     list->next = listlist;
  84.     listlist = list;
  85.     /* Make a window for the list, give it scrollbars. */
  86.     list->window = GetNewWindow(wList, nil, (WindowPtr) -1L);
  87.     stagger_window(list->window, &lastlisth, &lastlistv);
  88.     ShowWindow(list->window);
  89.     SetPort(list->window);
  90.     /* Create the scrollbars. */
  91.     hscrollrect = list->window->portRect;
  92.     hscrollrect.top = hscrollrect.bottom - sbarwid;
  93.     hscrollrect.bottom += 1;
  94.     hscrollrect.left = fixedfieldwidth - 1;
  95.     hscrollrect.right -= sbarwid - 1;
  96.     list->hscrollbar = NewControl(list->window, &hscrollrect, "\p", TRUE,
  97.                                    0, 0, 100, scrollBarProc, 0L);
  98.     vscrollrect = list->window->portRect;
  99.     vscrollrect.top = listtoph - 1;
  100.     vscrollrect.bottom -= sbarwid - 1;
  101.     vscrollrect.left = vscrollrect.right - sbarwid;
  102.     vscrollrect.right += 1;
  103.     list->vscrollbar = NewControl(list->window, &vscrollrect, "\p", TRUE,
  104.                                    0, 0, 100, scrollBarProc, 0L);
  105.     /* Now set the scrollbars to their *real* limits. */
  106.     set_list_scrollbars(list);
  107.     sprintf(spbuf, "List %d", listnum++);
  108.     add_window_menu_item(spbuf, list->window);
  109. }
  110.  
  111. /* Make the list be empty. */
  112.  
  113. void
  114. init_list_contents(List *list)
  115. {
  116.     /* Set up a unit vector with a first cut at needed space;
  117.        will adjust upwards automatically if necessary. */
  118.     list->contents = make_unit_vector(numunits + 50);
  119.     list->numunits = 0;
  120. }
  121.  
  122. /* This takes the list and fills in the items it is to display. */
  123.  
  124. void
  125. organize_list_contents(List *list)
  126. {
  127.     Side *side2;
  128.     Unit *unit;
  129.  
  130.     /* Build up the array of units for this list. */
  131.     list->numunits = 0;
  132.     clear_unit_vector(list->contents);
  133.     /* We always see our own units. */
  134.     for_all_side_units(dside, unit) {
  135.         add_unit_to_list(list, unit);
  136.     }
  137.     for_all_sides(side2) {
  138.         if (dside != side2) {
  139.             for_all_side_units(side2, unit) {
  140.                 if (side_sees_image(dside, unit)) {
  141.                     add_unit_to_list(list, unit);
  142.                 }
  143.             }
  144.         }
  145.     }
  146.     for_all_side_units(indepside, unit) {
  147.         if (side_sees_image(dside, unit)) {
  148.             add_unit_to_list(list, unit);
  149.         }
  150.     }
  151.     /* Now sort the list according to its keys. */
  152.     sort_list_contents(list);
  153. }
  154.  
  155. void
  156. sort_list_contents(List *list)
  157. {
  158.     int i;
  159.  
  160.     for (i = 0; i < MAXSORTKEYS; ++i) {
  161.         tmpsortkeys[i] = list->sortkeys[i];
  162.     }
  163.     sort_unit_vector(list->contents);
  164. }
  165.  
  166. void
  167. add_unit_to_list(List *list, Unit *unit)
  168. {
  169.     if (alive(unit)) {
  170.         list->contents = add_unit_to_vector(list->contents, unit, FALSE);
  171.         /* (should apply other inclusion criteria too?) */
  172.         ++list->numunits;
  173.     }
  174. }
  175.  
  176. /* Calculate reasonable/valid values and maxima for the scrollbars,
  177.    starting from the window size. */
  178.  
  179. void
  180. set_list_scrollbars(List *list)
  181. {
  182.     int numvisunits, visfieldwidth, val, maxval;
  183.     Rect winrect = list->window->portRect;
  184.  
  185.     /* Set the vertical scrollbar correctly. */    
  186.     numvisunits = (winrect.bottom - winrect.top - sbarwid - listtoph) / list->entryspacing;
  187.     maxval = max(0, list->numunits - numvisunits);
  188.     val = GetCtlValue(list->vscrollbar);
  189.     SetCtlMax(list->vscrollbar, maxval);
  190.     if (val > maxval) {
  191.         SetCtlValue(list->vscrollbar, maxval);
  192.         list->firstvisible = maxval;
  193.     }
  194.     /* Set up the horizontal scrollbar. */
  195.     visfieldwidth = winrect.right - winrect.left - sbarwid - fixedfieldwidth;
  196.     val = GetCtlValue(list->hscrollbar);
  197.     maxval = (maxlistwidth - fixedfieldwidth) - visfieldwidth;
  198.     maxval = max(0, maxval);
  199.     SetCtlMax(list->hscrollbar, maxval);
  200.     if (val > maxval) {
  201.         SetCtlValue(list->hscrollbar, maxval);
  202.         list->firstvisfield = maxval;
  203.     }
  204. }
  205.  
  206. List *
  207. list_from_window(WindowPtr window)
  208. {
  209.     List *list;
  210.     
  211.     if (dside == NULL) return NULL;
  212.     for_all_lists(list) {
  213.         if (list->window == window) return list;
  214.     }
  215.     return NULL;
  216. }
  217.  
  218. void
  219. draw_list(List *list)
  220. {
  221.     WindowPtr listwin = list->window;
  222.     Rect tmprect, cliprect;
  223.     RgnHandle tmprgn;
  224.  
  225.     tmprgn = NewRgn();
  226.     GetClip(tmprgn);
  227.     tmprect = listwin->portRect;
  228.     tmprect.right -= sbarwid;
  229.     tmprect.bottom -= sbarwid;
  230.     BackPat(QDPat(white));
  231.     EraseRect(&tmprect);
  232.     /* Set up clipping for the contents of the list. */
  233.     cliprect = listwin->portRect;
  234.     cliprect.right -= sbarwid;
  235.     tmprect.bottom -= sbarwid;
  236.     ClipRect(&cliprect);
  237.     TextSize(9);
  238.     draw_list_contents(list);
  239.     SetClip(tmprgn);
  240.     DisposeRgn(tmprgn);
  241. }
  242.  
  243. void
  244. draw_list_contents(List *list)
  245. {
  246.     int line, numvisunits, viswidth;
  247.     Rect winrect = list->window->portRect;
  248.  
  249.     /* Image is basically square, but add a bit of extra space on each side. */
  250.     imagecolw = list->entryspacing + 2;
  251.     /* Draw the selection and sorting as a sort of header. */
  252.     draw_list_headings(list);
  253.     /* Compute how many list elements are actually visible. */
  254.     numvisunits = (winrect.bottom - winrect.top - listtoph - sbarwid) / list->entryspacing;
  255.     numvisunits = min(numvisunits, list->numunits);
  256.     list->lastvisible = list->firstvisible + numvisunits - 1;
  257.     for (line = list->firstvisible; line <= list->lastvisible; ++line) {
  258.         draw_unit_list_entry(list, line, FALSE);
  259.     }
  260.     HiliteControl(list->vscrollbar, ((numvisunits < list->numunits) ? 0 : 255));
  261.     viswidth = winrect.right - winrect.left - sbarwid;
  262.     HiliteControl(list->hscrollbar, ((viswidth < maxlistwidth) ? 0 : 255));
  263. }
  264.  
  265. void
  266. draw_list_headings(List *list)
  267. {
  268.     int x = 0, m;
  269.     Str255 tmpstr;
  270.     Rect cliprect, tmprect, winrect = list->window->portRect;
  271.     RgnHandle tmprgn;
  272.  
  273.     /* Save the current clip region. */
  274.     tmprgn = NewRgn();
  275.     GetClip(tmprgn);
  276.     cliprect = winrect;
  277.     cliprect.right -= sbarwid;
  278.     ClipRect(&cliprect);
  279.     /* Clear the heading area. */
  280.     SetRect(&tmprect, 0, 0, winrect.right - sbarwid, listtoph);
  281.     EraseRect(&tmprect);
  282.     /* Draw dividing lines that cross both fixed and scrolling fields. */
  283.     MoveTo(0, listtoph - 3);
  284.     Line(winrect.right, 0);
  285.     MoveTo(0, listtoph - 1);
  286.     Line(winrect.right, 0);
  287.     /* (should underline sort keys with varying line heaviness) */
  288.     /* We have to do MoveTo everywhere because DrawString moves the pen. */
  289.     /* First draw headings for fields not affected by horizontal scrolling. */
  290.     x += curactcolw;
  291.     MoveTo(x, listtopbaseline);
  292.     DrawString("\ps/L");
  293.     x += imagecolw;
  294.     MoveTo(x, listtopbaseline);
  295.     DrawString("\pName/Number");
  296.     /* Shift left by horiz scroll. */
  297.     x -= list->firstvisfield;
  298.     /* Now clip against the fixed fields' area. */
  299.     cliprect = winrect;
  300.     cliprect.right -= sbarwid;
  301.     cliprect.left = fixedfieldwidth;
  302.     ClipRect(&cliprect);
  303.     x += namecolw;
  304.     MoveTo(x, listtopbaseline);
  305.     DrawString("\pType");
  306.     x += typecolw;
  307.     MoveTo(x, listtopbaseline);
  308.     DrawString("\pSide");
  309.     x += sidecolw;
  310.     MoveTo(x, listtopbaseline);
  311.     DrawString("\pHp");
  312.     x += hpcolw;
  313.     MoveTo(x, listtopbaseline);
  314.     DrawString("\pAcp");
  315.     x += acpcolw;
  316.     MoveTo(x, listtopbaseline);
  317.     DrawString("\pLoc");
  318.     x += poscolw;
  319.     for_all_material_types(m) {
  320.         MoveTo(x, listtopbaseline);
  321.         c2p(m_type_name(m), tmpstr);
  322.         DrawString(tmpstr);
  323.         x += supcolw;
  324.     }
  325.     MoveTo(x, listtopbaseline);
  326.     DrawString("\pNotes");
  327.     x += notecolw;
  328.     /* Draw a gray line indicating the end of the data columns. */
  329.     PenPat(QDPat(gray));
  330.     MoveTo(x, 0);
  331.     Line(0, listtoph - 4);
  332.     PenNormal();
  333.     /* Restore the clipping. */
  334.     SetClip(tmprgn);
  335.     DisposeRgn(tmprgn);
  336. }
  337.  
  338. /* This draws a one-line entry for the given unit. */
  339.  
  340. /* This routine does *not* save/restore the clip region, but does
  341.    modify it, so it should not be used except in a safe context. */
  342.  
  343. void
  344. draw_unit_list_entry(List *list, int n, int clearfirst)
  345. {
  346.     int u, m, x, y = (n - list->firstvisible) * list->entryspacing + listtoph;
  347.     int texty = y + 15;
  348.     char tmpnbuf[BUFSIZE];
  349.     Side *side2;
  350.     Rect entryrect, tmprect;
  351.     Unit *unit = list->contents->units[n].unit;
  352.     Rect cliprect;
  353.     Rect bbox = (*(list->window->visRgn))->rgnBBox;
  354.  
  355.     SetRect(&entryrect, 0, y, list->window->portRect.right, y + list->entryspacing);
  356. #if 0
  357.     /* (should use rect intersection?) */
  358.     if (!between(bbox.top, y, bbox.bottom)
  359.         && !between(bbox.top, y+list->entryspacing, bbox.bottom)) return;
  360. #endif
  361.     cliprect = list->window->portRect;
  362.     cliprect.right -= sbarwid;
  363.     ClipRect(&cliprect);
  364.  
  365.     if (clearfirst) {
  366.         EraseRect(&entryrect);
  367.     }
  368.     if (unit == NULL || !alive(unit)) {
  369.         /* We need to recalculate the list contents. */
  370.         list->shouldreorg = TRUE;
  371.         return;
  372.     }
  373.     u = unit->type;
  374.     /* Draw whether the unit is awake or asleep. */
  375.     if (unit->plan && completed(unit)) {
  376.         SetRect(&tmprect, 0, y + list->entryspacing/2 - curactcolw/2,
  377.                 curactcolw, y + list->entryspacing/2 + curactcolw/2);
  378.         InsetRect(&tmprect, 2, 2);
  379.         /* (should draw the following analogously to map display) */
  380.         if (unit->plan->asleep) {
  381.             /* Leave rectangle blank. */
  382.         } else if (unit->plan->reserve) {
  383.             FillRect(&tmprect, QDPat(gray));
  384.         } else {
  385.             FillRect(&tmprect, QDPat(black));
  386.         }
  387.         FrameRect(&tmprect);
  388.     }
  389.     /* Draw an icon with side emblem for this unit. */
  390.     draw_unit_image(list->window, curactcolw + 2, y + 1,
  391.                     (list->largeicons ? 32 : 16), (list->largeicons ? 32 : 16),
  392.                     u, side_number(unit->side), !completed(unit));
  393.     /* Write the name or ordinal number. */
  394.     name_or_number(unit, spbuf);
  395.     spbuf[15] = '\0';  /* (should be clipping by pixels) */
  396.     x = curactcolw + imagecolw;
  397.     MoveTo(x, texty);
  398.     DrawText(spbuf, 0, strlen(spbuf));
  399.     /* Adjust according to the horizontal scroll. */
  400.     x -= list->firstvisfield;
  401.     cliprect = list->window->portRect;
  402.     cliprect.right -= sbarwid;
  403.     cliprect.left = fixedfieldwidth;
  404.     ClipRect(&cliprect);
  405.     /* Write the name of the unit's type. */
  406.     x += namecolw;
  407.     MoveTo(x, texty);
  408.     sprintf(spbuf, "%s", u_type_name(u));
  409.     spbuf[10] = '\0';
  410.     DrawText(spbuf, 0, strlen(spbuf));
  411.     /* Write the side of the unit. */
  412.     x += typecolw;
  413.     MoveTo(x, texty);
  414.     side2 = unit->side;
  415.     strcpy(tmpnbuf, shortest_side_title(side2, spbuf));
  416.     tmpnbuf[15] = '\0'; /* truncate long side names */
  417.     DrawText(tmpnbuf, 0, strlen(tmpnbuf));
  418.     /* Draw the current hit points of the unit. */
  419.     x += sidecolw;
  420.     if (side_sees_unit(dside, unit)) {
  421.         MoveTo(x, texty);
  422.         hp_desc(spbuf, unit, FALSE);
  423.         DrawText(spbuf, 0, strlen(spbuf));
  424.     }
  425.     x += hpcolw;
  426.     if (side_sees_unit(dside, unit)) {
  427.         MoveTo(x, texty);
  428.         acp_desc(spbuf, unit, FALSE);
  429.         if (strlen(spbuf) == 0) strcpy(spbuf, "-");
  430.         DrawText(spbuf, 0, strlen(spbuf));
  431.     }
  432.     /* Draw the location. */
  433.     x += acpcolw;
  434.     MoveTo(x, texty);
  435.     sprintf(spbuf, "%d,%d", unit->x, unit->y);
  436.     if (unit->z != 0) {
  437.         tprintf(spbuf, ",%d", unit->z);
  438.     }
  439.     DrawText(spbuf, 0, strlen(spbuf));
  440.     /* Draw the state of all the supplies. */
  441.     x += poscolw;
  442.     if (side_sees_unit(dside, unit)) {
  443.         for_all_material_types(m) {
  444.             MoveTo(x, texty);
  445.             sprintf(spbuf, "%d", unit->supply[m]);
  446.             DrawText(spbuf, 0, strlen(spbuf));
  447.             x += supcolw;
  448.         }
  449.     } else {
  450.         x += nummtypes * supcolw; /* actually not necessary since no more cols */
  451.     }
  452.     /* Fix the clipping. */
  453.     cliprect = list->window->portRect;
  454.     cliprect.right -= sbarwid;
  455.     ClipRect(&cliprect);
  456.     /* Highlight this entry if it was selected. */
  457.     if (list->contents->units[n].flag) {
  458.         InvertRect(&entryrect);
  459.     }
  460. }
  461.  
  462. void
  463. grow_list(List *list, int w, int h)
  464. {
  465.     WindowPtr listwin = list->window;
  466.  
  467.     SizeWindow(listwin, w, h, 1);
  468.     adjust_list_decor(list);
  469.     InvalRect(&listwin->portRect);
  470. }
  471.  
  472. /* Zooming works like a list view in the Finder - it calculates a "perfect" size,
  473.    showing as much as possible but with no wasted blank areas. */
  474.  
  475. void
  476. zoom_list(List *list, int part)
  477. {
  478.     int maxh;
  479.     WindowPtr listwin = list->window;
  480.  
  481.     if (part == inZoomOut) {
  482.         maxh = listtoph + list->numunits * list->entryspacing + sbarwid;
  483.         set_standard_state(listwin, maxlistwidth, maxh);
  484.     }
  485.     EraseRect(&listwin->portRect);
  486.     ZoomWindow(listwin, part, true);
  487.     adjust_list_decor(list);
  488. }
  489.  
  490. /* Move and size the scrollbars to reflect the list's window. */
  491.  
  492. void
  493. adjust_list_decor(List *list)
  494. {
  495.     int w, h;
  496.  
  497.     w = list->window->portRect.right - list->window->portRect.left;
  498.     h = list->window->portRect.bottom - list->window->portRect.top;
  499.     MoveControl(list->vscrollbar, w - sbarwid, listtoph - 1);
  500.     SizeControl(list->vscrollbar, sbarwid + 1, h - listtoph - sbarwid + 1);
  501.     MoveControl(list->hscrollbar, fixedfieldwidth - 1, h - sbarwid);
  502.     SizeControl(list->hscrollbar, w - fixedfieldwidth - sbarwid + 1, sbarwid + 1);
  503.     set_list_scrollbars(list);
  504. }
  505.  
  506. /* Temporary used by scroll procs (saves looking up from the control). */
  507.  
  508. List *curlist;
  509.  
  510. pascal void
  511. list_vscroll_proc(ControlHandle control, short code)
  512. {
  513.     int curvalue, minvalue, maxvalue, oldvalue, pagesize, jump;
  514.     RgnHandle tmprgn;
  515.     Rect tmprect;
  516.     WindowPtr listwin = curlist->window;
  517.  
  518.     curvalue = oldvalue = GetCtlValue(control);
  519.     minvalue = GetCtlMin(control);
  520.     maxvalue = GetCtlMax(control);
  521.     pagesize = curlist->lastvisible - curlist->firstvisible + 1;
  522.     switch (code) {
  523.         case inPageDown:
  524.             jump = max(1, pagesize - 1);
  525.             break;
  526.         case inDownButton:
  527.             jump = 1;
  528.             break;
  529.         case inPageUp:
  530.             jump = min(-1, - (pagesize - 1));
  531.             break;
  532.         case inUpButton:
  533.             jump = -1;
  534.             break;
  535.         default:
  536.             jump = 0;
  537.             break;
  538.     }
  539.     curvalue = max(min(curvalue + jump, maxvalue), minvalue);
  540.     curlist->firstvisible = curvalue;
  541.     curlist->lastvisible = min(curlist->numunits, curlist->firstvisible + pagesize) - 1;
  542.     SetCtlValue(control, curvalue);
  543.     /* Scroll the already-drawn bits. */
  544.     tmprgn = NewRgn();
  545.     SetRect(&tmprect, 0, listtoph, listwin->portRect.right - sbarwid, listwin->portRect.bottom - sbarwid);
  546.     ScrollRect(&tmprect, 0, (oldvalue - curvalue) * curlist->entryspacing, tmprgn);
  547.     InvalRgn(tmprgn);
  548.     /* We'll need to redraw the headings line. */
  549.     draw_list_headings(curlist);
  550.     /* Do the update now, because we won't get back to the main event loop
  551.        until the mouse button is released. */
  552.     update_window(curlist->window);
  553.     DisposeRgn(tmprgn);
  554. }
  555.  
  556. pascal void
  557. list_hscroll_proc(ControlHandle control, short code)
  558. {
  559.     int curvalue, minvalue, maxvalue, oldvalue, pagesize, jump;
  560.     RgnHandle tmprgn;
  561.     Rect tmprect;
  562.     WindowPtr listwin = curlist->window;
  563.  
  564.     oldvalue = GetCtlValue(control);
  565.     minvalue = GetCtlMin(control);
  566.     maxvalue = GetCtlMax(control);
  567.     pagesize = curlist->lastvisfield - curlist->firstvisfield;
  568.     switch (code) {
  569.         case inPageDown:
  570.             jump = pagesize - 10;
  571.             break;
  572.         case inDownButton:
  573.             jump = 10;
  574.             break;
  575.         case inPageUp:
  576.             jump = - (pagesize - 10);
  577.             break;
  578.         case inUpButton:
  579.             jump = -10;
  580.             break;
  581.         default:
  582.             jump = 0;
  583.             break;
  584.     }
  585.     curvalue = max(min(oldvalue + jump, maxvalue), minvalue);
  586.     curlist->firstvisfield = curvalue;
  587.     curlist->lastvisfield = curlist->firstvisfield + pagesize;
  588.     SetCtlValue(control, curvalue);
  589.     /* Scroll the already-drawn bits. */
  590.     tmprgn = NewRgn();
  591.     SetRect(&tmprect, 0, listtoph, listwin->portRect.right - sbarwid, listwin->portRect.bottom - sbarwid);
  592.     ScrollRect(&tmprect, 0, (oldvalue - curvalue) * curlist->entryspacing, tmprgn);
  593.     InvalRgn(tmprgn);
  594.     /* We'll need to redraw the headings line. */
  595.     draw_list_headings(curlist);
  596.     /* Do the update now, because we won't get back to the main event loop
  597.        until the mouse button is released. */
  598.     update_window(curlist->window);
  599.     DisposeRgn(tmprgn);
  600. }
  601.  
  602. /* Handle a mouse down in the list.  Grafport already set, mouse coords are local. */
  603.  
  604. /* (mouse downs should select/deselect list elements) */
  605.  
  606. void
  607. do_mouse_down_list(List *list, Point mouse, int mods)
  608. {
  609.     ControlHandle control;
  610.     short part;
  611.     int n, tmp;
  612.     WindowPtr window = list->window;
  613.  
  614.     part = FindControl(mouse, window, &control);
  615.     if (control == list->vscrollbar) {
  616.         switch (part) {
  617.             case inThumb:
  618.                 part = TrackControl(control, mouse, NULL);
  619.                 if (part == inThumb) {
  620.                     list->firstvisible = GetCtlValue(control);
  621.                     force_update(window);
  622.                 }
  623.                 break;
  624.             default:
  625.                 curlist = list;
  626.                 part = TrackControl(control, mouse, (ProcPtr) list_vscroll_proc);
  627.                 list->firstvisible = GetCtlValue(control);
  628.                 break;
  629.         }
  630.     } else if (control == list->hscrollbar) {
  631.         switch (part) {
  632.             case inThumb:
  633.                 part = TrackControl(control, mouse, NULL);
  634.                 if (part == inThumb) {
  635.                     list->firstvisfield = GetCtlValue(control);
  636.                     force_update(window);
  637.                 }
  638.                 break;
  639.             default:
  640.                 curlist = list;
  641.                 part = TrackControl(control, mouse, (ProcPtr) list_hscroll_proc);
  642.                 list->firstvisfield = GetCtlValue(control);
  643.                 break;
  644.         }
  645.     } else {
  646.         if (mouse.v < listtoph) {
  647.             if (between(curactcolw, mouse.h, curactcolw + imagecolw)) {
  648.                 toggle_list_large_icons(list);
  649.             }
  650.             /* do others eventually */
  651.         } else {
  652.             /* Figure out the selected unit. */
  653.             n = (mouse.v - listtoph) / list->entryspacing + list->firstvisible;
  654.             tmp = list->contents->units[n].flag;
  655.             clear_selections(list);
  656.             list->contents->units[n].flag = !tmp;
  657.             redraw_unit_list_entry(list, n);
  658.         }
  659.     }
  660. }
  661.  
  662. void
  663. set_list_sorting(List *list, enum sortkeys newkey, int mi)
  664. {
  665.     int i;
  666.     
  667.     if (newkey != list->sortkeys[0]) {
  668.         /* Push all the existing sortkeys back - this way they'll can be
  669.            used as tiebreakers for the new sort key. */
  670.         for (i = MAXSORTKEYS - 1; i > 0; --i) {
  671.             list->sortkeys[i] = list->sortkeys[i - 1];
  672.         }
  673.         /* Add the new one onto the front. */
  674.         list->sortkeys[0] = newkey;
  675.         sort_list_contents(list);
  676.         force_update(list->window);
  677.         /* Record the menu item so it can get a checkmark during menu adjust. */
  678.         list->mainsortmi = mi;
  679.     }
  680. }
  681.  
  682. void
  683. toggle_list_large_icons(List *list)
  684. {
  685.     list->largeicons = !list->largeicons;
  686.     list->entryspacing = (list->largeicons ? largeentryspacing : smallentryspacing);
  687.     force_update(list->window);
  688. }
  689.  
  690. void
  691. update_unit_in_lists(Unit *unit)
  692. {
  693.     int line;
  694.     List *list;
  695.  
  696.     for_all_lists(list) {
  697.         if ((line = unit_position_in_list(list, unit)) >= 0) {
  698.             if (between(list->firstvisible, line, list->lastvisible)) {
  699.                 redraw_unit_list_entry(list, line);
  700.             }
  701.         } else {
  702.             /* (should attempt to insert at the correct location) */
  703.             add_unit_to_list(list, unit);
  704.             force_update(list->window);
  705.         }
  706.     }
  707. }
  708.  
  709. int
  710. unit_position_in_list(List *list, Unit *unit)
  711. {
  712.     int i;
  713.     
  714.     for (i = 0; i < list->numunits; ++i) {
  715.         if (unit == list->contents->units[i].unit) return i;
  716.     }
  717.     return (-1);
  718. }
  719.  
  720. void
  721. reorganize_list(List *list)
  722. {
  723.     organize_list_contents(list);
  724.     force_update(list->window);
  725. }
  726.  
  727. void
  728. redraw_unit_list_entry(List *list, int n)
  729. {
  730.     WindowPtr listwin;
  731.     Rect cliprect;
  732.     GrafPtr oldport;
  733.     RgnHandle tmprgn;
  734.  
  735.     if (!active_display(dside) || list == NULL) return;
  736.  
  737.     listwin = list->window;
  738.      GetPort(&oldport);
  739.     SetPort(listwin);
  740.     tmprgn = NewRgn();
  741.     GetClip(tmprgn);
  742.     /* Set up clipping for the contents of the list. */
  743.     cliprect = listwin->portRect;
  744.     cliprect.right -= sbarwid;
  745.     ClipRect(&cliprect);
  746.     TextSize(9);
  747.     draw_unit_list_entry(list, n, TRUE);
  748.     SetClip(tmprgn);
  749.     DisposeRgn(tmprgn);
  750.     SetPort(oldport);
  751. }
  752.  
  753. void
  754. clear_selections(List *list)
  755. {
  756.     int i;
  757.     
  758.     for (i = 0; i < list->numunits; ++i) {
  759.         if (list->contents->units[i].flag) {
  760.             list->contents->units[i].flag = FALSE;
  761.             redraw_unit_list_entry(list, i);
  762.         }
  763.     }
  764. }
  765.  
  766. Unit *
  767. selected_unit_in_list(List *list)
  768. {
  769.     int i;
  770.     
  771.     for (i = 0; i < list->numunits; ++i) {
  772.         if (list->contents->units[i].flag) return list->contents->units[i].unit;
  773.     }
  774.     return NULL;
  775. }
  776.  
  777. /* This finds a good map to scroll over to look at a unit mentioned in the list. */
  778.  
  779. void
  780. scroll_to_selected_unit_in_list(List *list)
  781. {
  782.     Unit *unit;
  783.  
  784.     /* Beep and return if there are no maps open currently. */
  785.     if (maplist == NULL) {
  786.         beep();
  787.         return;
  788.     }
  789.     unit = selected_unit_in_list(list);
  790.     if (unit != NULL && inside_area(unit->x, unit->y))
  791.       scroll_best_map_to_unit(unit);
  792. }
  793.  
  794. void
  795. activate_list(List *list, int activate)
  796. {
  797.     Rect growRect;
  798.  
  799.     if (activate) {
  800.         HiliteControl(list->vscrollbar, 0);
  801.         HiliteControl(list->hscrollbar, 0);
  802. #if 0
  803.         /* the controls must be redrawn on activation: */
  804.         (*(list->vscrollbar))->contrlVis = 255;
  805.         (*(list->hscrollbar))->contrlVis = 255;
  806.         InvalRect(&(*(list->vscrollbar))->contrlRect);
  807.         InvalRect(&(*(list->hscrollbar))->contrlRect);
  808. #endif
  809.         /* The growbox needs to be redrawn on activation. */
  810.         growRect = list->window->portRect;
  811.         /* adjust for the scrollbars */
  812.         growRect.top = growRect.bottom - sbarwid;
  813.         growRect.left = growRect.right - sbarwid;
  814.         InvalRect(&growRect);
  815.     } else {
  816.         /* The scrollbars must be hidden on deactivation. */
  817.         HiliteControl(list->vscrollbar, 255);
  818.         HiliteControl(list->hscrollbar, 255);
  819. /*        HideControl(list->vscrollbar);
  820.         HideControl(list->hscrollbar); */
  821.         /* The growbox should be changed immediately on deactivation. */
  822.         DrawGrowIcon(list->window);
  823.     }
  824. }
  825.  
  826. void
  827. print_list(List *list)
  828. {
  829. #if 0
  830.     TPPrPort printport;
  831.     extern THPrint printrecordhandle;
  832.  
  833.     printport = PrOpenDoc(printrecordhandle, nil, nil);
  834.     PrCloseDoc(printport);
  835. #endif
  836. }
  837.  
  838. /* Remove and destroy the list object. */
  839.  
  840. void
  841. destroy_list(List *list)
  842. {
  843.     List *list2;
  844.     
  845.     if (listlist == list) {
  846.         listlist = list->next;
  847.     } else {
  848.         for_all_lists(list2) {
  849.             if (list2->next == list) {
  850.                 list2->next = list->next;
  851.             }
  852.         }
  853.     }
  854.     /* (should destroy substructs) */
  855.     free(list);
  856. }
  857.